﻿using System;
using System.Collections;
using System.Collections.Generic;
using GameCreator.Messages;
using NRFramework;
using QFramework;
using UnityEngine;
using UnityEngine.EventSystems;

namespace Gp.Scripts.Core
{
    public enum UIPanelLayer
    {
        /// 背景
        BG = 1,

        /// 通用
        COMMON = 2,

        /// 弹窗
        POPUP = 3,

        /// 提示
        TIPS = 4,

        /// 全覆盖
        OVERLAY = 5
    }

    [AutoLoad]
    public partial class GUIManager : BaseGameManager
    {
        private UISystemConfig UIConfig => Global.Get<UISystemConfig>();
        private Dictionary<UIPanelLayer, GUIRoot> _panelRootMap;

        public Canvas UIMainCanvas { get; private set; }
        public Camera UICamera { get; private set; }
        public EventSystem UnityEventSystem { get; private set; }

        private Transform _uiPool;
        private Transform GUIManagerRoot { get; set; }
        private Dictionary<UIPanelLayer, Stack<string>> _uiStackMap;

        protected override void OnInit()
        {
            GUIManagerRoot = new GameObject("GUIManagerRoot").transform;
            GameEntry.Instance.DontDestroy(GUIManagerRoot);
            // 载入   UI    组件
            UICamera                 = Helpers.ResHelper.LoadBasic<Camera>("BasicUICamera").Instantiate();
            UIMainCanvas             = Helpers.ResHelper.LoadBasic<Canvas>("BasicUICanvas").Instantiate();
            UnityEventSystem         = Helpers.ResHelper.LoadBasic<EventSystem>("EventSystem").Instantiate();
            UIMainCanvas.renderMode  = RenderMode.ScreenSpaceCamera;
            UIMainCanvas.worldCamera = UICamera;
            _uiPool                  = new GameObject("UI_Pool").transform;
            UIMainCanvas.name        = "MainUICanvas";
            UICamera.name            = "UICamera";
            UnityEventSystem.name    = "EventSystem";

            UICamera.transform.SetParent(GUIManagerRoot, false);
            UIMainCanvas.transform.SetParent(GUIManagerRoot, false);
            UnityEventSystem.transform.SetParent(GUIManagerRoot, false);
            _uiPool.SetParent(GUIManagerRoot, false);
            UICamera.gameObject.SetActive(true);


            _panelRootMap = new Dictionary<UIPanelLayer, GUIRoot>();
            _uiStackMap   = new Dictionary<UIPanelLayer, Stack<string>>();
            
            foreach (UIPanelLayer layerId in Enum.GetValues(typeof(UIPanelLayer)))
            {
                _uiStackMap[layerId] = new Stack<string>();
                
                var prefix = Enum.GetName(typeof(UIPanelLayer), layerId);
                var uiRoot = new GameObject($"UI_{prefix}").AddComponent<GUIRoot>();
                var canvas = uiRoot.gameObject.AddComponent<Canvas>();
                
                canvas.sortingOrder    = (int) layerId * 100;
                _panelRootMap[layerId] = uiRoot;
                
                uiRoot.Init(UICamera, canvas);
                uiRoot.transform.SetParent(UIMainCanvas.transform, false);
                var rectTrans = canvas.transform as RectTransform;
                // TODO YHK : 包装成工具类
                rectTrans.anchorMax = new Vector2(1, 1);
                rectTrans.anchorMin = new Vector2(0, 0);
                rectTrans.offsetMax = Vector2.zero;
                rectTrans.offsetMin = Vector2.zero;
            }
        }


        public UIPanel PushPanel(string targetPanelId)
        {
            var info = UIConfig.GetPanelInfo(targetPanelId);
            if (TryGetStackPeek(info.PanelLayer, out string peekId))
            {
                if (peekId == targetPanelId)
                    Log($"panel {peekId} is already on the top");
                else
                    _panelRootMap[info.PanelLayer].ClosePanel(peekId);
            }

            Log($"push panel {targetPanelId}");
            var panel = OpenPanel(targetPanelId);
            GetUIStack(info.PanelLayer)?.Push(targetPanelId);
            return panel;
        }


        private UIPanel OpenPanel(string panelId)
        {
            var panelInfo = UIConfig.GetPanelInfo(panelId);
            var uiRoot    = _panelRootMap[panelInfo.PanelLayer];
            // 当前处于开启状态
            if (uiRoot.PanelDict.ContainsKey(panelId))
            {
                uiRoot.PanelDict[panelId].SetVisible(true);
                return uiRoot.PanelDict[panelId];
            }

            // 对象池存在
            if (GUIRoot.UIPool.ContainsKey(panelId))
            {
                var behaviour = PopPanelFromPool(panelId);
                return uiRoot.CreatePanelSoftly(panelInfo.ClassType, panelInfo.Id, behaviour);
            }
            // 新建
            else
            {
                return uiRoot.CreatePanel(panelInfo.ClassType, panelInfo.Id, panelInfo.PrefabPath);
            }
        }


        public UIPanel OpenPopup(string popupId)
        {
            var info = UIConfig.GetPanelInfo(popupId);
            if (info.PanelLayer != UIPanelLayer.POPUP)
            {
                throw new Exception($"Panel {popupId} is not a popup panel");
            }

            return JumpPanel(popupId);
        }

        public T OpenPopup<T>(string popupId) where T : UIPanel
        {
            var ret = OpenPanel(popupId);
            if (ret is not T tRet)
                throw new Exception($"Panel {popupId} is not of type {typeof(T)}, but found {ret.GetType().Name}");
            return tRet;
        }

        
        public UIPanel JumpPanel(string targetPanelId)
        {
            var info = UIConfig.GetPanelInfo(targetPanelId);
            if (TryGetStackPeek(info.PanelLayer, out string peekId))
            {
                _panelRootMap[info.PanelLayer].ClosePanel(peekId);
            }

            GetUIStack(info.PanelLayer)?.Clear();
            Log($"jump panel {targetPanelId}");
            return PushPanel(targetPanelId);
        }

        
        public void PopPanel(UIPanelLayer layerId = UIPanelLayer.COMMON)
        {
            if (TryGetStackPeek(layerId, out string peekId))
            {
                var info = UIConfig.GetPanelInfo(peekId);
                _panelRootMap[info.PanelLayer].ClosePanel(peekId);
            }

            if (TryGetStackPeek(layerId, out string newPeek))
            {
                OpenPanel(newPeek);
            }
        }

        public bool IsPeekPanel(string panelId)
        {
            return TryGetStackPeek(UIConfig.GetPanelInfo(panelId).PanelLayer, out string peekId) && peekId == panelId;
        }


        private UIPanelBehaviour PopPanelFromPool(string panelId)
        {
            var panelBehaviour = GUIRoot.UIPool[panelId];
            panelBehaviour.gameObject.SetActive(true);
            GUIRoot.UIPool.Remove(panelId);
            return panelBehaviour as UIPanelBehaviour;
        }

        private Stack<string> GetUIStack(UIPanelLayer layerId)
        {
            return _uiStackMap.GetValueOrDefault(layerId);
        }

        private bool TryGetStackPeek(UIPanelLayer layerId, out string peekId)
        {
            peekId = string.Empty;
            return _uiStackMap.TryGetValue(layerId, out Stack<string> stack) && stack.TryPeek(out peekId);
        }


        public void Tips(string msg, float duration = 2f)
        {
            _panelRootMap[UIPanelLayer.TIPS].StartCoroutine(Cor());

            IEnumerator Cor()
            {
                SimpleMessageManager.Instance.ShowText(msg, Color.white);
                yield return new WaitForSeconds(duration);
                SimpleMessageManager.Instance.HideText();
            }
        }
    }
}